﻿using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.Owin;
using Microsoft.Owin.Security;
using Newtonsoft.Json;
using Sharp.DataTransferObject;
using Sharp.Infrastructure;
using Sharp.Infrastructure.WebApiClient;
using Sharp.Portal.Configuration;
using Sharp.Portal.Mvc;
using Sharp.Portal.Mvc.OAuth.Sharp.Server;
using Sharp.Portal.Owin;
using Sharp.ServiceContracts;
using Sharp.WebBooter.Areas.Platform.Models;
// ReSharper disable Mvc.ViewNotResolved

namespace Sharp.WebBooter.Areas.Platform.Controllers
{
    //[Authorize]
    public class AccountController : SharpController
    {

        public AccountController()
        {
        }


        //
        // GET: /Account/Login
        [AllowAnonymous]
        public ActionResult Login(string returnUrl)
        {
            Response.Expires = 0;
            Response.Buffer = true;
            Response.ExpiresAbsolute = DateTime.Now.AddSeconds(-1);
            Response.AddHeader("pragma", "no-cache");
            Response.CacheControl = "no-cache";
            
            AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);
            ViewBag.ReturnUrl = returnUrl;

            LoginViewModel model = new LoginViewModel();

            model.FailCount = Convert.ToInt32(Session["TryLoginFailCount"]);
            return View(model);
        }


        //
        // POST: /Account/Login
        [System.Web.Mvc.HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
        {
            if (!ModelState.IsValid)
            {
                return View(model);
            }
            ViewBag.ReturnUrl = returnUrl;

            model.FailCount = Convert.ToInt32(Session["TryLoginFailCount"]);
            if (model.FailCount > 1)
            {
                if (System.Web.HttpContext.Current.Session["ValidateCode"] == null)
                {
                    ModelState.AddModelError("", "验证码失效，请重新登录");
                    return View(model);
                }
                if (System.Web.HttpContext.Current.Session["ValidateCode"].ToString() != model.ValidateCode)
                {
                    ModelState.AddModelError("", "验证码错误");
                    return View(model);
                }
            }

            #region 获取AccessToken
            var clientId = SystemConfigManage.Read<PlatformInfo>().ClientId;
            var clientSecret = SystemConfigManage.Read<PlatformInfo>().ClientSecret;

            var accessToken = await OAuthKit.GetAccessTokenAsync(clientId, clientSecret, model.Name, model.Password);
            #endregion

            Result<UserDTO> res;
            using (var proxy = new WebApiClientServiceProxy<IUserService>())
            {
                res = proxy.Channel.TryLogin(new UserDTO()
                {
                    UserName = model.Name,
                    Password = model.Password,
                    LastLogonIp = WebServer.GetIP()
                });
            }
            if (res.Err.Length > 0)
            {
                model.FailCount += 1;
                Session["TryLoginFailCount"] = model.FailCount;

                ModelState.AddModelError("", res.Err);
                return View(model);
            }
            Session.Remove("TryLoginFailCount");

            SharpUserManager.Current = new SharpUser(res.Data);
#if !DEBUG
            if (WebServer.GetIP() != "127.0.0.1")
            {
                SharpUserManager.Current.Permissions.RemoveAll(x => x.SystemCode == "Demo");
            }
#endif

            ClaimsIdentity id = ClaimsIdentityCreate.GenerateUserIdentity(new SharpUser(res.Data), DefaultAuthenticationTypes.ApplicationCookie);
            id.AddClaim(new Claim("AccessToken", accessToken));

            AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = true }, id);

            if (returnUrl.IsNullOrEmpty())
                return Redirect("~/");
            return Redirect(returnUrl);
        }
        /// <summary>
        /// 退出
        /// </summary>
        /// <returns></returns>
        public ActionResult LogOff()
        {
            AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);
            return Redirect("~/Login");
        }

        #region 验证码

        [AllowAnonymous]
        public ActionResult GetValidateCode()
        {
            ValidateCode vCode = new ValidateCode();
            string code = vCode.CreateValidateCode(4);
            Session["ValidateCode"] = code;
            byte[] bytes = vCode.CreateValidateGraphic(code);
            return File(bytes, @"image/jpeg");
        }

        #endregion

        /// <summary>
        /// 忘记密码
        /// </summary>
        /// <returns></returns>
        public ActionResult ForgotPassword()
        {
            var model = new ForgotPasswordViewModel();
            return View("ForgotPassword", model);
        }

        /// <summary>
        /// 取回密码
        /// </summary>
        /// <param name="vm"></param>
        /// <returns></returns>
        public ActionResult ForgotPassword(ForgotPasswordViewModel vm)
        {
            using (var proxy = new WebApiClientServiceProxy<IUserService>())
            {
                var dto = vm.To<ForgotPasswordDTO>();
                dto.Email = vm.Email;
                dto.CallBackUrl = HttpContext.Request.Url.Authority;

                var res = proxy.Channel.ForgotPassword(dto);
                vm.Message = res.Message;

                return View(vm);
            }
        }

        /// <summary>
        /// 重置密码
        /// </summary>
        /// <param name="token">防伪识别码</param>
        /// <returns></returns>
        public ActionResult ResetPassword(Guid token)
        {
            var vm = new ResetPasswordViewModel
            {
                Token = token.ToString()
            };
            return View(vm);
        }

        /// <summary>
        /// 重置密码
        /// </summary>
        /// <param name="vm"></param>
        /// <returns></returns>
        public ActionResult ResetPassword(ResetPasswordViewModel vm)
        {
            if (vm == null)
            {
                ModelState.AddModelError("", "提交数据出错。");
                return View(new ResetPasswordViewModel());
            }
            Result res;
            using (var proxy = new WebApiClientServiceProxy<IUserService>())
            {
                res = proxy.Channel.ResetPassword(vm.To<ResetPasswordDTO>());
            }

            if (res.Err.Length > 0)
                ModelState.AddModelError("", res.Err);

            return View(vm);
        }


        /// <summary>
        /// 保存订阅项配置
        /// </summary>
        /// <returns></returns>
        public ActionResult SaveSubscriber(Guid[] subscriberIds)
        {
            var res = new Result();
            try
            {
                var userId = SharpUserManager.Current.Id;
                var config = UserConfigManage.Read<UserConfigInfo>(userId);
                config.Subscribers.Clear();
                for (var i = 0; i < subscriberIds.Length; i++)
                {
                    config.Subscribers.Add(new UserConfigInfo.SubscriberItem()
                    {
                        Id = subscriberIds[i],
                        Order = i
                    });
                }

                UserConfigManage.Save(config);
            }
            catch (Exception ex)
            {
                res.InnerException = ex;
            }
            return this.JsonNet(res);
        }


        public ActionResult ChangePassword()
        {
            var model = new ChangePassword();
            return View("ChangePassword", model);
        }

        public ActionResult ChangePassword(ChangePassword vm)
        {
            if (vm == null)
            {
                return this.JsonNet(new Result { Err = "提交数据出错。" });
            }
            if (vm.PasswordNew != vm.PasswordNewS)
            {
                return this.JsonNet(new Result { Err = "两次输入新密码不一致，请重新输入！" });

            }
            using (var proxy = new WebApiClientServiceProxy<IUserService>())
            {

                var res = proxy.Channel.ChangePassword(SharpUserManager.Current.UserName, vm.Password, vm.PasswordNew);

                return this.JsonNet(res);
            }
        }

        #region 帮助程序
        private SharpSignInManager _signInManager;
        private SharpUserManager _userManager;
        // 用于在添加外部登录名时提供 XSRF 保护
        private const string XsrfKey = "XsrfId";
        public SharpSignInManager SignInManager
        {
            get => _signInManager ?? HttpContext.GetOwinContext().Get<SharpSignInManager>();
            set => _signInManager = value;
        }

        public SharpUserManager UserManager
        {
            get => _userManager ?? HttpContext.GetOwinContext().GetUserManager<SharpUserManager>();
            set => _userManager = value;
        }
        private IAuthenticationManager AuthenticationManager => HttpContext.GetOwinContext().Authentication;

        private void AddErrors(IdentityResult result)
        {
            foreach (var error in result.Errors)
            {
                ModelState.AddModelError("", error);
            }
        }

        internal class ChallengeResult : HttpUnauthorizedResult
        {
            public ChallengeResult(string provider, string redirectUri)
                : this(provider, redirectUri, null)
            {
            }

            public ChallengeResult(string provider, string redirectUri, string userId)
            {
                LoginProvider = provider;
                RedirectUri = redirectUri;
                UserId = userId;
            }

            public string LoginProvider { get; set; }
            public string RedirectUri { get; set; }
            public string UserId { get; set; }

            public override void ExecuteResult(ControllerContext context)
            {
                var properties = new AuthenticationProperties { RedirectUri = RedirectUri };
                if (UserId != null)
                {
                    properties.Dictionary[XsrfKey] = UserId;
                }
                context.HttpContext.GetOwinContext().Authentication.Challenge(properties, LoginProvider);
            }
        }
        #endregion

        #region 外部登录
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public ActionResult ExternalLogin(string provider, string returnUrl)
        {
            // Request a redirect to the external login provider
            return new ChallengeResult(
                provider,
                Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl }), null);
        }

        //
        // GET: /Account/ExternalLoginCallback
        [AllowAnonymous]
        public async Task<ActionResult> ExternalLoginCallback(string returnUrl)
        {
            var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();
            if (loginInfo == null)
            {
                return RedirectToAction("Login");
            }

            // Sign in the user with this external login provider if the user already has a login
            var user = await UserManager.FindAsync(loginInfo.Login);
            if (user != null)
            {
                await SignInAsync(user, isPersistent: false);
                return RedirectToLocal(returnUrl);
            }
            else
            {
                // If the user does not have an account, then prompt the user to create an account
                ViewBag.ReturnUrl = returnUrl;
                ViewBag.LoginProvider = loginInfo.Login.LoginProvider;
                return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { UserName = loginInfo.DefaultUserName });
            }
        }

        private async Task SignInAsync(SharpUser user, bool isPersistent)
        {
            AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
            var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
            AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity);
        }
        private ActionResult RedirectToLocal(string returnUrl)
        {
            if (Url.IsLocalUrl(returnUrl))
            {
                return Redirect(returnUrl);
            }
            else
            {
                return RedirectToAction("Index", "Home");
            }
        }

   
        #endregion


    }
}